perm filename HOST.FAI[S,NET]9 blob sn#828471 filedate 1986-11-12 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00006 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	 A B C X Y P PDLEN HSTSID HSTFN1 HSTVRS HSTDIR HSTDEV HSTWHO HSTDAT HSTTIM NAMPTR SITPTR NETPTR NTNPTR HDRLEN NETNUM NTLNAM NTRTAB NETLEN ADDADR ADLSIT ADRCDR ADLXXX ADRSVC SVLCNT SVRCDR SVLFLG SVRNAM SVCARG ADDLEN STLNAM STRADR STLSYS STRMCH STLFLG STFSRV STFGWY SITLEN NMLSIT NMRNAM NAMLEN NNLNET NNRNAM NTNLEN NT$NUM NE%UNT NE%STR NN%IP NW%ARP NW%SI NW%SU HSTFIL HSTPPN
C00015 00003	 START GETCOM FLSINP HSTCOM CMDSCN PROMPT DOCMD HSTLUP GOTHST GETNUM GETNU1 GETNU2 GETNU3 GETNU4 GETNU5 GETNU6 NOTIPH HSTLUZ ALPHST DOSRCH SEARCH SRCLT SRCGT SRCDUN SRCDU1 SRCDU2 COMPAR PRINT OFFNAM NAMLP NAMDUN MCHTYP ENDNIC
C00029 00004	 GETHST ATTHST ATTHS0 ATTHS2 ATTCRE ATTMUL ATTUPP ATTLOW ATTERR MXATTE HSGNAM MAPHS2 MAPHST MAPHS0 MAPHS4 MAPHS3
C00038 00005	 HSTNUM HSTNUS HSTNU1
C00040 00006	 SWINIR SWINR1 SWINR2 SWINIP SWINP1 PRHNUM PRHNIP PRDECP PRDEC PROCT PRLOOP PDL MONCMP NOHOST PASS1 EXACT HSTADR HSTTOP HSTEXT CRLF CPOPJ2 CPOPJ1 CPOPJ
C00045 ENDMK
C⊗;
;⊗ A B C X Y P PDLEN HSTSID HSTFN1 HSTVRS HSTDIR HSTDEV HSTWHO HSTDAT HSTTIM NAMPTR SITPTR NETPTR NTNPTR HDRLEN NETNUM NTLNAM NTRTAB NETLEN ADDADR ADLSIT ADRCDR ADLXXX ADRSVC SVLCNT SVRCDR SVLFLG SVRNAM SVCARG ADDLEN STLNAM STRADR STLSYS STRMCH STLFLG STFSRV STFGWY SITLEN NMLSIT NMRNAM NAMLEN NNLNET NNRNAM NTNLEN NT$NUM NE%UNT NE%STR NN%IP NW%ARP NW%SI NW%SU HSTFIL HSTPPN

	TITLE HOST

;This program is adapted from the old HOST.MID, which read the HOSTS1.BIN
;file, and from various code in NETWRK.FAI.  NETWRK isn't inserted directly,
;because we want to do slightly different things in searching for host names.

Comment ⊗

12 Nov 86  JJW	Changed MAPHST to GETHST, which calls ATTHST to attach
		high segment and then copies table into low segment.

⊗ ;end of history

A←12				;Our AC's don't interfere with NETWRK's
B←13
C←14
X←15
Y←16
P←17

PDLEN←←20

;The format of the host table binary file is:

HSTSID←←0	; wd 0	SIXBIT /HOSTS3/
HSTFN1←←1	; wd 1	SIXBIT FN1 of source file (eg HOSTS)
HSTVRS←←2	; wd 2	SIXBIT FN2 of source file (TNX: version #)
HSTDIR←←3	; wd 3  SIXBIT directory name of source file (eg SYSENG)
HSTDEV←←4	; wd 4  SIXBIT device name of source file (eg AI)
HSTWHO←←5	; wd 5	SIXBIT login name of person who compiled this
HSTDAT←←6	; wd 6  SIXBIT Date of compilation as YYMMDD
HSTTIM←←7	; wd 7	SIXBIT Time of compilation as HHMMSS
NAMPTR←←10	; wd 10 Fileaddress of NAME table.
SITPTR←←11	; wd 11	Fileaddress of SITE table.
NETPTR←←12	; wd 12 Fileaddress of NETWORK table.
NTNPTR←←13	; wd 13 Fileaddress of NETNAME table.
		;....expandable....
  HDRLEN←←14	; length of header

; NETWORK table
;	wd 0	Number of entries in table.
;	wd 1	Number of words per entry. (2)
; This table contains one entry for each known network.
; It is sorted by network number.
; Each entry contains:

NETNUM←←0	; wd 0 network number (full netaddr)
NTLNAM←←1	; wd 1 LH - fileaddr of ASCIZ name of network
NTRTAB←←1	; wd 1 RH - fileaddr of network's ADDRESS table
 NETLEN←←2

; ADDRESS table(s)
;	wd 0	Number of entries in table.
;	wd 1	Number of words per entry. (3)
; There is one of these tables for each network.  It contains entries
; for each site attached to that network, sorted by network address.
; These tables are used to convert a numeric address into a host name.
; Also, the list of network addresses and services for a site is stored
; within these tables.
; Each entry contains:

ADDADR←←0	; wd 0	Network address of this entry, in HOSTS3 fmt.
ADLSIT←←1	; wd 1 LH - fileaddr of SITE table entry
ADRCDR←←1	; wd 1 RH - fileaddr of next ADDRESS entry for this site
		;	 0 = end of list
ADLXXX←←2	; wd 2 LH - unused
ADRSVC←←2	; wd 2 RH - fileaddr of services list for this address
		;	0 = none, else points to SERVICE node of format:
	SVLCNT←←0	;		<# wds>,,<fileaddr of next, or 0>
	SVRCDR←←0
	SVLFLG←←1	;		<flags>,,<fileaddr of svc name>
	SVRNAM←←1
	SVCARG←←2	;		<param1> ? <param2> ? ...
 ADDLEN←←3

; SITE table
;	wd 0	Number of entries in table.
;	wd 1	Number of words per entry. (3)
; This table contains entries for each network site,
; not sorted by anything in particular. A site can have more
; than one network address, usually on different networks.
; This is the main, central table.
; Each entry looks like:

STLNAM←←0	; wd 0 LH - fileaddr of official host name
STRADR←←0	; wd 0 RH - fileaddr of first ADDRESS table entry for this
		;		site.  Successive entries are threaded
		;		together through ADRCDR.
STLSYS←←1	; wd 1 LH - fileaddr of system name (ITS, TIP, TENEX, etc.)
		;		May be 0 → not known.
STRMCH←←1	; wd 1 RH - fileaddr of machine name (PDP10, etc.)
		;		May be 0 → not known.
STLFLG←←2	; wd 2 LH - flags:
STFSRV←←400000	;	4.9 1 → server site (has FTP or TELNET)
STFGWY←←200000	;	4.8 1 → Internet Gateway site (HOSTS3 only)
 SITLEN←←3

; NAMES table:
;	wd 0	Number of entries
;	wd 1	Number of words per entry. (1)
; This table is used to convert host names into network addresses.  It
; contains entries sorted alphabetically by host name.

NMLSIT←←0	; wd 0 LH - fileaddr of SITE table entry for this host.
NMRNAM←←0	; wd 0 RH - fileaddr of host name
		; This name is official if NMRNAM = STLNAM of NMLSIT.
 NAMLEN←←1

; NETNAME table:
;	wd 0	Number of entries
;	wd 1	Number of words per entry. (1)
; This table is used to convert network names into network numbers.  It
; contains entries sorted alphabetically by network name, exactly as
; for the NAMES table.  Although the symbols below are different (in order
; to make semantic distinctions), programs can depend on the fact
; that the NETNAME table format is identical to that of the NAMES table.

NNLNET←←0	; wd 0 LH - fileaddr of NETWORK table entry for this host.
NNRNAM←←0	; wd 0 RH - fileaddr of network name
 NTNLEN←←1

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;		HOSTS3 Network Address Format           ;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

comment |
HOSTS3 network address format:

   4.9-4.6 - 4 bits of format type, which specify interpretation of
		the remaining 32 bits.
IN	0000 - Internet address (handles ARPA, RCC, LCS)
		4.5-1.1 - 32 bits of IN address.
UN	0001 - Unternet address.  Same format, but not part of Internet.
		4.5-3.7 - HOSTS3-defined network number (1st 8-bit byte)
		3.6-1.1 - address value in next 24 bits.
			This handles CHAOS and any local nets.  The network
			numbers are unique within the HOSTS3 table but
			don't necessarily mean anything globally, as do
			Internet network numbers.
	0011 - String address.
		4.5-3.7 - HOSTS3-defined network number (1st 8-bit byte)
		3.6-3.1 - 0
		2.9-1.1 - address of ASCIZ string in file/process space

Note that the "network number" for all of these formats is located in
the same place.  However, for fast deciphering of the entire range of
possibilities, one could simply consider all of the high 12 bits as the
network number.  Beware of the Internet class A, B, and C formats, though;
the only truly general way to compare network numbers is to use their
masked 36-bit values, although simpler checks are OK for specific nets.
For this reason (among others) network numbers are represented by
full 36-bit values with the "local address" portion zero.

The 4-bit "String address" value is much more tentative than the IN or UN
values.  Bit 4.9, the sign bit, is being reserved as usual for the possible
advent of a truly spectacular incompatible format.
|

NT$NUM←←301400		;Byte pointer to network number (high 12 bits)
NE%UNT←←<040000,,0>	;Escape bit indicating "Unternet" type address
NE%STR←←<100000,,0>	;Escape bit indicating "string" type address
NN%IP←←<740000,,0>	;host number bits that are off for all IP addresses
NW%ARP←←<12⊗=24>	;HOSTS3 uses full word network # values
NW%SI←←44⊗=24		;Internet address of SU-NET-TEMP
NW%SU←←NE%UNT+NW%SI	;"Unternet" used for Stanford Ethernet


DEFINE GETNET(AC,ADDR)<
IFDIF <ADDR><><MOVE AC,ADDR>
	TLNN AC,(17⊗=32)	; Check for non-Internet type addrs
	 TLNN AC,(1⊗=31)	;  Internet address, see if class A net
	  TDZA AC,[77,,-1]	;   Unternet or class A, zap low 3 octets
	TLNN AC,(1⊗=30)		; Class B or C, see which.
	 TRZA AC,177777		;  Class B network, zap low 2 octets
	  TRZ AC,377		;   Class C net, only zap 1 low octet
>;GETNET

HSTFIL:	SIXBIT/HOSTS3/		;filename and extension of binary file
	SIXBIT/BIN/
HSTPPN:	SIXBIT/HSTNET/		;PPN of binary file
;⊗ START GETCOM FLSINP HSTCOM CMDSCN PROMPT DOCMD HSTLUP GOTHST GETNUM GETNU1 GETNU2 GETNU3 GETNU4 GETNU5 GETNU6 NOTIPH HSTLUZ ALPHST DOSRCH SEARCH SRCLT SRCGT SRCDUN SRCDU1 SRCDU2 COMPAR PRINT OFFNAM NAMLP NAMDUN MCHTYP ENDNIC

START:	CAI
	RESET
	SETZM MONCMP
	MOVE P,[IOWD PDLEN,PDL]
	PUSHJ P,GETHST		;Map host table in core
	RESCAN A
	JUMPE A,PROMPT
GETCOM:	INCHRS X
	 JRST PRMPT0
	CAIE X," "		;Skip whitespace
	 CAIN X,11
	  JRST GETCOM
	CAIE X,"H"		;Check for HOST command
	 CAIN X,"h"
	  JRST HSTCOM
FLSINP:	INCHRS X
	 JRST PRMPT0
	CAIE X,175
	 CAIN X,12
	  JRST PRMPT0
	JRST FLSINP

HSTCOM:	OUTSTR CRLF
CMDSCN:	INCHRS X
	 JRST GOTHST
	CAIE X,175
	 CAIN X,12
	  JRST GOTHST		;No command argument
	CAIE X," "
	 JRST CMDSCN
	SETOM MONCMP
	JRST DOCMD

PRMPT0:	GETPPN A,
	CAME A,['100100']
PROMPT:	SKIPE MONCMP
	 EXIT 1,
	OUTSTR [ASCIZ/
Host name or number: /]
DOCMD:	SETZM HSTEXT
	MOVE Y,[POINT 7,HSTEXT]
HSTLUP:	INCHWL X
	ANDI X,177
	CAIN X,15
	 INCHWL X
	CAIE X,175
	 CAIN X,12
	  JRST GOTHST
	IDPB X,Y
	JRST HSTLUP

GOTHST:	SETZ X,
	IDPB X,Y
;Here with input text string in HSTEXT.
	SKIPN HSTEXT
	 JRST PRMPT0
	MOVE Y,[POINT 7,HSTEXT]	;Start at beginning of text
	ILDB X,Y		;Now see if we got a name or a number
	CAIL X,"0"
	 CAILE X,"9"
	  JRST ALPHST		;Alphabetic host specification
	PUSHJ P,SWINIP		;Get host number
	 JRST NOTIPH		;Not an IP host number
	JUMPN X,HSTLUZ
	MOVE 0,B		;Set up for HSTNUM
GETNUM:	PUSHJ P,HSTNUM		;Look up the number
	 JRST GETNU2		;Not found
GETNU1:	HLRZ 6,STLNAM(7)	;Get official name
	ADD 6,HSTADR
	OUTSTR (6)
	PUSHJ P,OFFNAM		;Finish typing host info
	JRST PROMPT

GETNU2:	HLRZ 0,B		;Get LH of host number
	ANDI 0,777700		;Just class-A network part
	CAIN 0,(NW%SU)		;Stanford PUP address?
	JRST GETNU4		;Yes, convert to IP
	CAIN 0,(NW%SI)		;Or Stanford IP?
	JRST GETNU5		;Yes, convert to PUP
GETNU3:	OUTSTR [ASCIZ/Unknown host
/]
	JRST PROMPT

GETNU4:	LDB 0,[POINT 8,B,27]	;Subnet number from PUP address
	LSH 0,=8		;Position for IP address
	JRST GETNU6

GETNU5:	LDB 0,[POINT 8,B,19]	;Subnet number from IP address
GETNU6:	DPB 0,[POINT 16,B,27]	;Store 2nd and 3 bytes
	TLC B,(NW%SU≠NW%SI)	;Change to the other network
	MOVE 0,B
	PUSHJ P,HSTNUM		;And look that up
	 JRST GETNU3		;Not there either
	JRST GETNU1		;Matched, sort of, so tell the user

;Here with a non-IP host number in A (octal) and B (decimal).
NOTIPH:	JUMPE X,[OUTSTR [ASCIZ/Incomplete host number specification
/]
		JRST PROMPT]
	CAIN X,"/"		;BBN style number?
	 JRST [	CAILE B,377
		 SETO B,
		PUSH P,B
		ILDB X,Y	;Check numericness
		CAIL X,"0"
		 CAILE X,"9"
		  JRST HSTLUZ
		PUSHJ P,SWINIR
		SKIPN B
		 SETZM (P)
		POP P,A		;A←host, B←IMP
		JUMPN X,HSTLUZ
		LSH A,=16
		ADDI A,(B)
		TLO A,(NW%ARP)	;Set network
		MOVE 0,A
		JRST GETNUM]
	CAIN X,"#"		;XEROX style number
	 JRST [	SKIPLE A
		CAILE A,377
		 JRST HSTLUZ
		PUSH P,A
		ILDB X,Y	;Check numericness
		CAIL X,"0"
		 CAILE X,"9"
		  JRST HSTLUZ
		PUSHJ P,SWINIR
		POP P,B		;B←subnet, A←host
		JUMPN X,HSTLUZ
		SKIPLE A
		CAILE A,377
		 JRST HSTLUZ
		LSH B,=8
		ADDI B,(A)
		TLO B,(NW%SU)	;Set network
		MOVE 0,B
		JRST GETNUM]
HSTLUZ:	OUTSTR [ASCIZ/Bad host number format
/]
	JRST PROMPT

;Here with an alphabetic host name.
ALPHST:	SETOM NOHOST		;Indicate no host found so far
	PUSHJ P,DOSRCH
	SKIPE NOHOST		;Did we print anything?
	 OUTSTR [ASCIZ/Unknown host name
/]
	JRST PROMPT

;Set up various AC's for search.
DOSRCH:	MOVE 0,[POINT 7,HSTEXT]
	MOVE 1,HSTADR
	MOVE 1,NAMPTR(1)
	ADD 1,HSTADR		;Address of NAMES table
	HRLI 1,2(1)		;<first entry>,,<addr of table>
	ADD 1,(1)		;<first entry>,,<last entry>+1
	PUSH P,1		;Save for use in SRCDUN
	SUBI 1,1		;<first entry>,,<last entry>
	SETZ 3,			;No partial match yet

;Host name search.  AC's during search hold the following:
;  0: byte pointer to source string
;  1: <beginning>,,<ending> of current range in NAMES table
;  2: current entry in NAMES table being tested
;  3: -1 if a partial match found
SEARCH:	HLRZ 2,1		;Beginning of current range
	CAILE 2,(1)		;Beyond end?
	 JRST SRCDUN		;Yes, search done
	ADDI 2,(1)		;Add beginning and ending
	LSH 2,-1		;Compute midpoint
	HRRZ 7,NMRNAM(2)
	ADD 7,HSTADR		;Pointer for this entry
	HRLI 7,440700
	MOVE 6,0		;Copy of source pointer
	PUSHJ P,COMPAR
	 JRST SRCGT
	 JRST SRCLT
	 JRST [	ADJSP P,-1	;Exact match!
		PUSHJ P,PRINT
		JRST UNFLAG]
	SETO 3,			;Partial match
;Here if source string less than table entry.
SRCLT:	HRRI 1,-1(2)		;Set end of range to before entry
	JRST SEARCH

;Here if source string greater than table entry.
SRCGT:	HRLI 1,1(2)		;Set beginning of range to after entry
	JRST SEARCH

;Here when binary search done.  2 contains first name that might match.
;Scan forward and compare until no more match, to get range of names.
SRCDUN:	POP P,1			;Get back <first entry>,,<last entry+1>
	JUMPE 3,CPOPJ		;Jump if no match
	PUSH P,2		;Remember first entry
	SUBM 2,1		;- <Max # of entries to check>
	HRL 2,1			;Make AOBJN ptr
SRCDU1:	HRRZ 7,NMRNAM(2)
	ADD 7,HSTADR		;Pointer for this entry
	HRLI 7,440700
	MOVE 6,0		;Copy of source pointer
	PUSHJ P,COMPAR
	 JRST SRCDU2
	 JRST SRCDU3		;Done
	 HALT .			;Exact match can't happen here!
SRCDU2:	AOBJN 2,SRCDU1		;Loop unless hit end of table
SRCDU3:	SUB 2,(P)		;# of matching entries
	MOVNI 2,(2)
	HRLM 2,(P)		;AOBJN ptr
	MOVE 2,(P)
	PUSHJ P,PRINT
	AOBJN 2,.-1
	POP P,2
	PUSHJ P,UNFLAG
	AOBJN 2,.-1
	POPJ P,

;Subroutine to compare two names given by byte pointers in 6 and 7.
;Returns: +1 if (6) .gt. (7)
;	  +2 if (6) .lt. (7) and is not a partial match
;	  +3 if (6) matches (7) exactly
;	  +4 if (6) matches a substring of (7)
;ACs 10 and 11 hold the most recent characters read from each string.
COMPAR:	ILDB 10,6		;Get next byte from each string
	ILDB 11,7
	JUMPE 10,[JUMPE 11,CPOPJ2	;Exact match
		  AOS (P)		;Partial match
		  JRST CPOPJ2]
	JUMPE 11,CPOPJ		;Partial match the other way
	CAIL 10,"a"		;Use upper case for comparisons
	 SUBI 10,40
	CAIL 11,"a"
	 SUBI 11,40
	CAIGE 10,(11)
	 AOSA (P)
	CAILE 10,(11)
	 POPJ P,
	JRST COMPAR		;Characters match, keep comparing

;Here to print information for a host.  Call with name table entry address in 2.

PRINT:	SETZM NOHOST		;We now have found a match
	HRRZ 5,NMRNAM(2)
	ADD 5,HSTADR
	HLRZ 7,NMLSIT(2)
	ADD 7,HSTADR
	MOVSI 10,1		;Pseudo-flag
	TDNE 10,STLFLG(7)	;Have we shown it already?
	 POPJ P,		;Yes
	IORM 10,STLFLG(7)	;Set pseudo-flag when we show a site
	HLRZ 6,STLNAM(7)
	ADD 6,HSTADR
	OUTSTR (5)
	CAIN 5,(6)
	 JRST OFFNAM		;Official name
	OUTSTR [ASCIZ/ is a nickname for /]
	OUTSTR (6)
	OUTSTR [ASCIZ/, which/]
;Enter here from GETNUM (host lookup by number) with site table entry in 7.
OFFNAM:	OUTSTR [ASCIZ/ is number /]
	HRRZ 6,STRADR(7)
NAMLP:	ADD 6,HSTADR
	MOVE X,ADDADR(6)
	PUSHJ P,PRHNUM
	HRRZ 6,ADRCDR(6)
	JUMPE 6,NAMDUN
	OUTSTR [ASCIZ/, /]
	JRST NAMLP
NAMDUN:	OUTSTR [ASCIZ/,
a /]
	SKIPL STLFLG(7)
	 SKIPA 10,[[ASCIZ/user /]]
	  MOVEI 10,[ASCIZ/server /]
	OUTSTR (10)
	HRRZ 6,STRMCH(7)
	JUMPE 6,[	OUTSTR [ASCIZ/unknown/]
			JRST MCHTYP]
	ADD 6,HSTADR
	OUTSTR (6)
MCHTYP:	OUTSTR [ASCIZ/ machine running /]
	HLRZ 6,STLSYS(7)
	JUMPE 6,[	OUTSTR [ASCIZ/an unknown operating system.

/]
			POPJ P,]
	ADD 6,HSTADR
	OUTSTR (6)
ENDNIC:	OUTSTR [ASCIZ/.

/]
	POPJ P,

UNFLAG:	HRRZ 5,NMRNAM(2)
	ADD 5,HSTADR
	HLRZ 7,NMLSIT(2)
	ADD 7,HSTADR
	MOVSI 10,1		;Pseudo-flag
	ANDCAM 10,STLFLG(7)	;Turn it off
	POPJ P,
;⊗ GETHST ATTHST ATTHS0 ATTHS2 ATTCRE ATTMUL ATTUPP ATTLOW ATTERR MXATTE HSGNAM MAPHS2 MAPHST MAPHS0 MAPHS4 MAPHS3

; GETHST -- Map host table into core
; Call:	PUSHJ 17,GETHST
;	<return>
; Smashes 0, 1, 2, and 3.

;Adapted from ATTHST and MAPHST in NETWRK.  (Removing fancy error recovery,
;mostly.)  We'd like to use the upper segment to avoid reading the host
;table from disk, but need to modify it, so we can't share it with other
;jobs.  The solution is to copy it into our lower segment.

GETHST:	PUSHJ 17,ATTHST		;Attach host table upper segment
	SKIPN 1,HSTTOP		;End address of table, if we read it
	HRRZ 1,JOBHRL↑		;Else make a conservative estimate
	SUB 1,HSTADR		;Length of table
	ADD 1,JOBFF↑		;New size for low segment
	CAILE 1,377777		;Will it fit?
	 JRST 4,.-1		;No.  (If this ever happens, use ordinary MAPHST.)
	MOVE 2,JOBFF		;Remember old JOBFF
	MOVEM 1,JOBFF		;Save new JOBFF
	CORE 1,			;Expand low segment
	 JRST 4,.-1
	MOVE 1,JOBFF
	MOVEM 1,HSTTOP
	HRL 2,HSTADR		;Set up BLT to copy from old HSTADR
	HRRZM 2,HSTADR		;Save new HSTADR before we clobber AC 2
	BLT 2,-1(1)		;Copy the table
	MOVEI 0,0
	CORE2 0,		;Flush high segment
	 JFCL
	POPJ 17,

;ATTHST -- Attach to upper segment that has the host table in it,
;	   or create one if necessary.
;Call:	PUSHJ 17,ATTHST
;	<return>
;Preserves ALL ACs.

ATTHST:	PUSH 17,3		;preserve all ACs
	MOVE 3,HSGNAM		;get upper segment name
ATTHS0:	ATTSEG 3,		;try to attach to segment
	 JRST ATTHS2		;failed, see why
	MOVEI 3,400000
	MOVEM 3,HSTADR		;set host table address
	POP 17,3
	POPJ 17,

ATTHS2:	HLLM 3,-1(17)		;save error code's left half
	ANDI 3,-1		;just error code
	CAIL 3,MXATTE		;reasonable error?
	MOVEI 3,MXATTE		;no
	JRST @ATTERR(3)		;dispatch on error

;Create upper segment and read host table into it.
ATTCRE:	PUSH 17,0
	PUSH 17,1
	PUSH 17,2
	PUSHJ 17,MAPHS2		;read host table into new upper segment, AC 3 already saved
	MOVEI 1,1
	SETUWP 1,		;write protect upper segment
	 JFCL			;error should never happen
	MOVE 1,HSGNAM
	SETNM2 1,		;rename it so others can share it
	 JFCL			;error should never happen
	POP 17,2
	POP 17,1
	POP 17,0
	POP 17,3
	POPJ 17,

;Attach one of multiple uppers with same name
ATTMUL:	HLRZ 3,-1(17)		;job number of one job with given name
	JRST ATTHS0		;try again

ATTUPP:	JRST 4,.

ATTLOW:	JRST 4,.

ATTERR:	ATTCRE			;protection violation, create new segment
	ATTMUL			;multiple upper segments, attach one
	ATTCRE			;no such upper segment job number
	ATTCRE			;no such upper segment job name
	ATTUPP			;already have an upper
	ATTLOW			;lower segment is too big
MXATTE←←.-ATTERR

HSGNAM:	SIXBIT/HOSTS!/		;name of upper segment

; MAPHST -- Map host table into core
; Call:	PUSHJ 17,MAPHST
;	<return>
; Smashes 0, 1, 2, and 3.

MAPHS2:	HRROS (17)	;indicate want host table in new upper segment
	JRST MAPHS0

MAPHST:	HRRZS (17)	;indicate want host table in lower segment
MAPHS0:	INIT 17
	 ('DSK')
	 0
	 JRST 4,.-3
	DMOVE 0,HSTFIL
	MOVE 3,HSTPPN
	LOOKUP 0
	 JRST 4,.-1
	MOVS 0,3		;unswap file length
	MOVN 0,0		;make file length positive
	SKIPGE (17)		;going into upper?
	JRST MAPHS3		;yes
	MOVE 2,JOBFF↑		;place to put table
	ADDB 0,JOBFF↑		;get address of highest addr we need
	MOVEM 0,HSTTOP
	CORE 0,			;get more core from system maybe
	 JRST 4,.-1
MAPHS4:	MOVE 0,3 		;negative length in LH
	HRRI 0,-1(2)		;compute IOWD to read host table in
	MOVEI 1,0
	INPUT 0			;read whole host table
	MOVE 0,(2)		;get first word of host table
	CAME 0,HSTFIL
	 JRST 4,.-1
	MOVEM 2,HSTADR		;remember where host table begins
	RELEAS
	POPJ 17,

MAPHS3:	MOVEI 2,400000		;place to put host table, beginning of upper
	ADDI 0,(2)		;ending address of table
	MOVEM 0,HSTTOP		;end of table
	CORE2 0,		;get enough core in upper segment
	 JRST 4,.-1
	JRST MAPHS4
;⊗ HSTNUM HSTNUS HSTNU1

; HSTNUM -- Return descriptor block for a host
; Call:	MOVEI <host number>
;	PUSHJ 17,HSTNUM
;	<error return--no such host>
;	<return--absolute NAMNUM in 0, NUMSYS,,NUMNAM in 1, NUMBTS,,NUMMCH in 2>
; Smashes 0, 1, 2, 3, and 4.

HSTNUM:	GETNET 4,0			; get network number
	SKIPN 4
	 TLO 0,(NW%ARP)			; if none given, assume ARPANet
	MOVE 1,HSTADR
	MOVE 1,NETPTR(1)
	PUSHJ 17,HSTNUS			; lookup network number
	  POPJ 17,
	MOVE 1,NTRTAB(1)		; get address table for network
	MOVEM 4				; thing to search for
	PUSHJ 17,HSTNUS			; lookup address
	  POPJ 17,
	HLRZ 7,ADLSIT(1)		; get site table entry
	ADD 7,HSTADR
	JRST CPOPJ1

HSTNUS:	ADD 1,HSTADR			; relocate table
	MOVE 2,(1)			; get # of entries
	MOVE 3,1(1)			; and entry size
	ADDI 1,2			; point at first entry
HSTNU1:	CAMN 4,(1)			; found it?
	  JRST CPOPJ1			;   yes, skip return for success
	ADD 1,3				; point at next entry
	SOJG 2,HSTNU1			; keep on searching
	POPJ P,				; failed
;⊗ SWINIR SWINR1 SWINR2 SWINIP SWINP1 PRHNUM PRHNIP PRDECP PRDEC PROCT PRLOOP PDL MONCMP NOHOST PASS1 EXACT HSTADR HSTTOP HSTEXT CRLF CPOPJ2 CPOPJ1 CPOPJ

;Some of these subroutines adapted from TELNET.FAI[S,NET].

;  Super winning numeric input routine.  Numbers are parsed as both octal and
; decimal, unless either (a) an 8 or 9 appears in the number, or (b) the number
; is followed by a decimal point.

SWINIR:	SETZB A,B			; A ← octal number, B ← decimal
SWINR1:	CAIL X,"8"			; if can't be octal, A ← -1
	 SETO A,
	JUMPL A,SWINR2
	LSH A,3
	ADDI A,-"0"(X)			; bring in next octal digit
SWINR2:	IMULI B,=10
	ADDI B,-"0"(X)			; bring in next decimal digit
	ILDB X,Y
	CAIN X,"."			; decimal point ends spec and forces decimal
	 JRST [	SETO A,
		ILDB X,Y
		POPJ P,]
	CAIL X,"0"
	 CAILE X,"9"
	  POPJ P,			; non-numeric, return
	JRST SWINR1

;Super winning IP host number parser.  If an IP host number is seen, then it will
;be returned in B and SWINIP will skip return.  Otherwise, just like SWINIR.

SWINIP:	PUSHJ P,SWINIR		;Parse a number
	CAIL X,"0"		;Check the next character
	CAILE X,"9"
	POPJ P,			;Not a digit, so not an IP host number
	PUSH P,B		;Save 1st byte
	PUSHJ P,SWINP1		;Get rest of IP host number left-adj in B
	POP P,A			;Restore 1st byte
	LSHC A,-=12		;Right-adjust entire number in B
	JRST CPOPJ1		;Skip to show IP host number

;Subroutine to return an IP host number left-adjusted in B.

SWINP1:	PUSHJ P,SWINIR		;Get a number
	PUSH P,B		;Save it
	CAIL X,"0"		;See if a digit follows
	CAILE X,"9"
	TDZA B,B		;No.  Zero B and skip
	PUSHJ P,SWINP1		;Yes, get rest of IP host in B
	POP P,A			;Get back current byte
	LSHC A,-=8		;Shift into rest of number
	POPJ P,

;Routine to print a host number, either in SU Ethernet or IP format.  Takes
;host number in X.
PRHNUM:	TLNE X,740000		;Non-Internet?
	 JRST PRHNIP		;Yes, print non-IP
	LDB A,[POINT 8,X,11]
	PUSHJ P,PRDEC		;Print first byte
	LDB A,[POINT 8,X,19]
	PUSHJ P,PRDECP		;Print period and second byte
	LDB A,[POINT 8,X,27]
	PUSHJ P,PRDECP		;Print period and third byte
	LDB A,[POINT 8,X,35]
	PUSHJ P,PRDECP		;Print period and fourth byte
	POPJ P,

PRHNIP:	HLRZ A,X		;Get left half of addr
	CAIE A,(NW%SU)		;SU-Net?
	 POPJ P,		;No, return quietly
	OUTSTR [ASCIZ/SU /]
	LDB A,[POINT 8,X,27]
	PUSHJ P,PROCT		;Print first byte
	OUTCHR ["#"]
	LDB A,[POINT 8,X,35]
	PUSHJ P,PROCT		;Print second byte
	POPJ P,

PRDECP:	OUTCHR ["."]
PRDEC:	SKIPA C,[=10]
PROCT:	MOVEI C,10
PRLOOP:	IDIV A,C
	PUSH P,B
	SKIPE A
	 PUSHJ P,PRLOOP
	POP P,A
	ADDI A,"0"
	OUTCHR A
	POPJ P,

PDL:	BLOCK PDLEN

MONCMP:	BLOCK 1			;-1 → got a monitor command
NOHOST:	BLOCK 1			;-1 → no host found so far
PASS1:	BLOCK 1			;-1 → in pass 1 of 2-pass search
EXACT:	BLOCK 1			;-1 → got an exact match

HSTADR:	BLOCK 1
HSTTOP:	BLOCK 1
HSTEXT:	BLOCK 25

CRLF:	BYTE (7)15,12

CPOPJ2:	AOS (P)
CPOPJ1: AOS (P)
CPOPJ:	POPJ P,

	END START